using System;
using System.Text.RegularExpressions;
using FluentValidation;
using Matrix.Configuration.DTOs;
using Volo.Abp.Validation;

namespace Matrix.Configuration.Application.Validation
{
    /// <summary>
    /// 配置项验证器
    /// </summary>
    public class ConfigurationItemValidator : AbstractValidator<ConfigurationItemDto>
    {
        public ConfigurationItemValidator()
        {
            RuleFor(x => x.Namespace)
                .NotEmpty()
                .MaximumLength(ConfigurationItemConsts.MaxNamespaceLength)
                .Matches(@"^[a-zA-Z][a-zA-Z0-9._-]*$")
                .WithMessage("命名空间必须以字母开头，只能包含字母、数字、点、下划线和短横线");

            RuleFor(x => x.Key)
                .NotEmpty()
                .MaximumLength(ConfigurationItemConsts.MaxKeyLength)
                .Matches(@"^[a-zA-Z][a-zA-Z0-9._-]*$")
                .WithMessage("配置键必须以字母开头，只能包含字母、数字、点、下划线和短横线");

            RuleFor(x => x.Value)
                .NotEmpty()
                .MaximumLength(ConfigurationItemConsts.MaxValueLength);

            RuleFor(x => x.DataType)
                .NotEmpty()
                .Must(BeValidDataType)
                .WithMessage("数据类型必须是支持的类型：string, int, bool, double, decimal, datetime, guid, json");

            RuleFor(x => x.Description)
                .MaximumLength(ConfigurationItemConsts.MaxDescriptionLength);
        }

        private bool BeValidDataType(string dataType)
        {
            if (string.IsNullOrEmpty(dataType))
                return false;

            return dataType.ToLowerInvariant() switch
            {
                "string" or "int" or "bool" or "double" or "decimal" or
                "datetime" or "guid" or "json" => true,
                _ => false
            };
        }
    }

    /// <summary>
    /// 创建配置项验证器
    /// </summary>
    public class CreateConfigurationItemValidator : AbstractValidator<CreateConfigurationItemDto>
    {
        public CreateConfigurationItemValidator()
        {
            RuleFor(x => x.Namespace)
                .NotEmpty()
                .MaximumLength(ConfigurationItemConsts.MaxNamespaceLength)
                .Matches(@"^[a-zA-Z][a-zA-Z0-9._-]*$")
                .WithMessage("命名空间必须以字母开头，只能包含字母、数字、点、下划线和短横线");

            RuleFor(x => x.Key)
                .NotEmpty()
                .MaximumLength(ConfigurationItemConsts.MaxKeyLength)
                .Matches(@"^[a-zA-Z][a-zA-Z0-9._-]*$")
                .WithMessage("配置键必须以字母开头，只能包含字母、数字、点、下划线和短横线");

            RuleFor(x => x.Value)
                .NotEmpty()
                .MaximumLength(ConfigurationItemConsts.MaxValueLength)
                .Custom(ValidateValueByType);

            RuleFor(x => x.DataType)
                .NotEmpty()
                .Must(BeValidDataType)
                .WithMessage("数据类型必须是支持的类型：string, int, bool, double, decimal, datetime, guid, json");

            RuleFor(x => x.Description)
                .MaximumLength(ConfigurationItemConsts.MaxDescriptionLength);
        }

        private bool BeValidDataType(string dataType)
        {
            if (string.IsNullOrEmpty(dataType))
                return false;

            return dataType.ToLowerInvariant() switch
            {
                "string" or "int" or "bool" or "double" or "decimal" or
                "datetime" or "guid" or "json" => true,
                _ => false
            };
        }

        private void ValidateValueByType(string value, ValidationContext<CreateConfigurationItemDto> context)
        {
            var dataType = context.InstanceToValidate.DataType?.ToLowerInvariant();

            if (string.IsNullOrEmpty(dataType))
                return;

            switch (dataType)
            {
                case "int":
                    if (!int.TryParse(value, out _) && !long.TryParse(value, out _))
                        context.AddFailure("值类型为int时，配置值必须是有效的整数");
                    break;

                case "bool":
                    if (!bool.TryParse(value, out _) &&
                        !value.Equals("true", StringComparison.OrdinalIgnoreCase) &&
                        !value.Equals("false", StringComparison.OrdinalIgnoreCase) &&
                        !value.Equals("1") && !value.Equals("0"))
                        context.AddFailure("值类型为bool时，配置值必须是true/false、1/0");
                    break;

                case "double":
                    if (!double.TryParse(value, out _) && !decimal.TryParse(value, out _))
                        context.AddFailure("值类型为double时，配置值必须是有效的数字");
                    break;

                case "decimal":
                    if (!decimal.TryParse(value, out _))
                        context.AddFailure("值类型为decimal时，配置值必须是有效的十进制数");
                    break;

                case "datetime":
                    if (!DateTime.TryParse(value, out _) &&
                        !DateTimeOffset.TryParse(value, out _) &&
                        !long.TryParse(value, out _)) // Unix timestamp
                        context.AddFailure("值类型为datetime时，配置值必须是有效的日期时间格式");
                    break;

                case "guid":
                    if (!Guid.TryParse(value, out _))
                        context.AddFailure("值类型为guid时，配置值必须是有效的GUID格式");
                    break;

                case "json":
                    if (!IsValidJson(value))
                        context.AddFailure("值类型为json时，配置值必须是有效的JSON格式");
                    break;
            }
        }

        private bool IsValidJson(string json)
        {
            try
            {
                System.Text.Json.JsonDocument.Parse(json);
                return true;
            }
            catch
            {
                return false;
            }
        }
    }

    /// <summary>
    /// 更新配置项验证器
    /// </summary>
    public class UpdateConfigurationItemValidator : AbstractValidator<UpdateConfigurationItemDto>
    {
        public UpdateConfigurationItemValidator()
        {
            RuleFor(x => x.Value)
                .MaximumLength(ConfigurationItemConsts.MaxValueLength)
                .Custom(ValidateValueByTypeWhenProvided);

            RuleFor(x => x.DataType)
                .Must(BeValidDataTypeWhenProvided)
                .WithMessage("数据类型必须是支持的类型：string, int, bool, double, decimal, datetime, guid, json");

            RuleFor(x => x.Description)
                .MaximumLength(ConfigurationItemConsts.MaxDescriptionLength);
        }

        private bool BeValidDataType(string dataType)
        {
            if (string.IsNullOrEmpty(dataType))
                return false;

            return dataType.ToLowerInvariant() switch
            {
                "string" or "int" or "bool" or "double" or "decimal" or
                "datetime" or "guid" or "json" => true,
                _ => false
            };
        }

        private bool BeValidDataTypeWhenProvided(string? dataType)
        {
            // 如果DataType为空，则不验证（允许部分更新）
            if (string.IsNullOrEmpty(dataType))
                return true;

            return BeValidDataType(dataType);
        }

        private void ValidateValueByTypeWhenProvided(string? value, ValidationContext<UpdateConfigurationItemDto> context)
        {
            // 如果Value为空，则不验证（允许部分更新）
            if (string.IsNullOrEmpty(value))
                return;

            var dataType = context.InstanceToValidate.DataType?.ToLowerInvariant();

            // 如果DataType也为空，则不验证值类型
            if (string.IsNullOrEmpty(dataType))
                return;

            switch (dataType)
            {
                case "int":
                    if (!int.TryParse(value, out _) && !long.TryParse(value, out _))
                        context.AddFailure("值类型为int时，配置值必须是有效的整数");
                    break;

                case "bool":
                    if (!bool.TryParse(value, out _) &&
                        !value.Equals("true", StringComparison.OrdinalIgnoreCase) &&
                        !value.Equals("false", StringComparison.OrdinalIgnoreCase) &&
                        !value.Equals("1") && !value.Equals("0"))
                        context.AddFailure("值类型为bool时，配置值必须是true/false、1/0");
                    break;

                case "double":
                    if (!double.TryParse(value, out _) && !decimal.TryParse(value, out _))
                        context.AddFailure("值类型为double时，配置值必须是有效的数字");
                    break;

                case "decimal":
                    if (!decimal.TryParse(value, out _))
                        context.AddFailure("值类型为decimal时，配置值必须是有效的十进制数");
                    break;

                case "datetime":
                    if (!DateTime.TryParse(value, out _) &&
                        !DateTimeOffset.TryParse(value, out _) &&
                        !long.TryParse(value, out _)) // Unix timestamp
                        context.AddFailure("值类型为datetime时，配置值必须是有效的日期时间格式");
                    break;

                case "guid":
                    if (!Guid.TryParse(value, out _))
                        context.AddFailure("值类型为guid时，配置值必须是有效的GUID格式");
                    break;

                case "json":
                    if (!IsValidJson(value))
                        context.AddFailure("值类型为json时，配置值必须是有效的JSON格式");
                    break;
            }
        }

        private bool IsValidJson(string json)
        {
            try
            {
                System.Text.Json.JsonDocument.Parse(json);
                return true;
            }
            catch
            {
                return false;
            }
        }
    }
}